#include "RedisCache.hpp"
#include <iostream>
#include <cstring>

RedisCache::RedisCache() : context_(nullptr) {}

RedisCache::~RedisCache() {
    if (context_ != nullptr) {
        redisFree(context_);
        context_ = nullptr;
    }
}

bool RedisCache::connect(const std::string& host, int port) {
    if (context_ != nullptr) {
        redisFree(context_);
        context_ = nullptr;
    }
    
    context_ = redisConnect(host.c_str(), port);
    if (context_ == nullptr || context_->err) {
        if (context_ != nullptr) {
            std::cerr << "Redis connection error: " << context_->errstr << std::endl;
            redisFree(context_);
            context_ = nullptr;
        } else {
            std::cerr << "Redis connection error: Can't allocate redis context" << std::endl;
        }
        return false;
    }
    return true;
}

bool RedisCache::set(const std::string& key, const std::string& value) {
    if (context_ == nullptr) return false;
    
    redisReply* reply = (redisReply*)redisCommand(context_, "SET %s %s", key.c_str(), value.c_str());
    if (reply == nullptr) return false;
    
    bool success = reply->type != REDIS_REPLY_ERROR;
    if (!success && reply->str != nullptr) {
        std::cerr << "Redis SET error: " << reply->str << std::endl;
    }
    
    freeReplyObject(reply);
    return success;
}

bool RedisCache::get(const std::string& key, std::string& value) {
    if (context_ == nullptr) return false;
    
    redisReply* reply = (redisReply*)redisCommand(context_, "GET %s", key.c_str());
    if (reply == nullptr) return false;
    
    bool success = false;
    if (reply->type == REDIS_REPLY_STRING) {
        value.assign(reply->str, reply->len);
        success = true;
    } else if (reply->type == REDIS_REPLY_NIL) {
        // Key不存在是正常情况，不是错误
        value.clear();
        success = true;
    } else if (reply->type == REDIS_REPLY_ERROR && reply->str != nullptr) {
        std::cerr << "Redis GET error: " << reply->str << std::endl;
    }
    
    freeReplyObject(reply);
    return success;
}

bool RedisCache::expire(const std::string& key, int seconds) {
    if (context_ == nullptr) return false;
    
    redisReply* reply = (redisReply*)redisCommand(context_, "EXPIRE %s %d", key.c_str(), seconds);
    if (reply == nullptr) return false;
    
    bool success = (reply->type == REDIS_REPLY_INTEGER && reply->integer == 1);
    if (!success && reply->str != nullptr) {
        std::cerr << "Redis EXPIRE error: " << reply->str << std::endl;
    }
    
    freeReplyObject(reply);
    return success;
}

// 其他命令的实现
bool RedisCache::del(const std::string& key) {
    if (context_ == nullptr) return false;
    
    redisReply* reply = (redisReply*)redisCommand(context_, "DEL %s", key.c_str());
    if (reply == nullptr) return false;
    
    bool success = (reply->type == REDIS_REPLY_INTEGER);
    freeReplyObject(reply);
    return success;
}

bool RedisCache::exists(const std::string& key) {
    if (context_ == nullptr) return false;
    
    redisReply* reply = (redisReply*)redisCommand(context_, "EXISTS %s", key.c_str());
    if (reply == nullptr) return false;
    
    bool success = (reply->type == REDIS_REPLY_INTEGER && reply->integer == 1);
    freeReplyObject(reply);
    return success;
}

bool RedisCache::hset(const std::string& key, const std::string& field, const std::string& value) {
    if (context_ == nullptr) return false;
    
    redisReply* reply = (redisReply*)redisCommand(context_, "HSET %s %s %s", 
                                                 key.c_str(), field.c_str(), value.c_str());
    if (reply == nullptr) return false;
    
    bool success = (reply->type == REDIS_REPLY_INTEGER);
    freeReplyObject(reply);
    return success;
}

bool RedisCache::hget(const std::string& key, const std::string& field, std::string& value) {
    if (context_ == nullptr) return false;
    
    redisReply* reply = (redisReply*)redisCommand(context_, "HGET %s %s", 
                                                 key.c_str(), field.c_str());
    if (reply == nullptr) return false;
    
    bool success = false;
    if (reply->type == REDIS_REPLY_STRING) {
        value.assign(reply->str, reply->len);
        success = true;
    } else if (reply->type == REDIS_REPLY_NIL) {
        value.clear();
        success = true;
    }
    
    freeReplyObject(reply);
    return success;
}

// 列表操作实现
bool RedisCache::lpush(const std::string& key, const std::string& value) {
    if (context_ == nullptr) return false;
    
    redisReply* reply = (redisReply*)redisCommand(context_, "LPUSH %s %s", key.c_str(), value.c_str());
    if (reply == nullptr) return false;
    
    bool success = (reply->type == REDIS_REPLY_INTEGER);
    freeReplyObject(reply);
    return success;
}

bool RedisCache::rpush(const std::string& key, const std::string& value) {
    if (context_ == nullptr) return false;
    
    redisReply* reply = (redisReply*)redisCommand(context_, "RPUSH %s %s", key.c_str(), value.c_str());
    if (reply == nullptr) return false;
    
    bool success = (reply->type == REDIS_REPLY_INTEGER);
    freeReplyObject(reply);
    return success;
}

bool RedisCache::lrange(const std::string& key, int start, int stop, std::vector<std::string>& values) {
    if (context_ == nullptr) return false;
    
    redisReply* reply = (redisReply*)redisCommand(context_, "LRANGE %s %d %d", key.c_str(), start, stop);
    if (reply == nullptr) return false;
    
    bool success = false;
    if (reply->type == REDIS_REPLY_ARRAY) {
        values.clear();
        for (size_t i = 0; i < reply->elements; i++) {
            if (reply->element[i]->type == REDIS_REPLY_STRING) {
                values.emplace_back(reply->element[i]->str, reply->element[i]->len);
            }
        }
        success = true;
    }
    
    freeReplyObject(reply);
    return success;
}